// Copyright (c) Appeon. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

using System;
using System.Collections;
using System.IO;
using System.Text;

namespace SnapObjects.Data
{
    internal class TNodeReader : INodeReader
    {
        private readonly IEnumerator _row;
        private readonly TextReader _reader;

        public static INodeReader Parse(string raw)
        {
            return new TNodeReader(raw);
        }

        public TNodeReader(string text)
        {
            if (String.IsNullOrWhiteSpace(text))
            {
                throw new Exception(Properties.Resource.DATAREADER_NOTNULL_EXCEPTION);
            }
            else
            {
                this.NodeType = DataNodeType.Array;

                _reader = new StringReader(text);
            }
        }

        private TNodeReader(string[] row)
        {
            _row = row.GetEnumerator();
        }

        public int Depth { get; private set; }
        public bool IsEnd { get; private set; }
        public bool IsEmpty { get; private set; }
        public string Name { get; private set; }
        public string CurrentNodeName { get; private set; }
        public DataNodeType NodeType { get; private set; }
        public DataNodeType CurrentNodeType { get; private set; }

        public IValueReader ValueReader
        {
            get
            {
                this.CheckEnd();

                if (this.CurrentNodeType != DataNodeType.Value)
                {
                    throw new FormatException($"Unexpected token '{_reader.Peek()}'.");
                }

                object current = null;

                if (!_row.Current.Equals("null"))
                {
                    current = this.TrimQuotation((string)_row.Current);
                }

                return new TValueReader(this.CurrentNodeName, current);
            }
        }

        public bool Read()
        {
            this.CheckEnd();

            this.CurrentNodeName = null;

            if (_reader != null)
            {
                if (_reader.Peek() < 0)
                {
                    this.IsEnd = true;
                    return false;
                }

                this.CurrentNodeType = DataNodeType.Object;
            }
            else
            {
                if (!_row.MoveNext())
                {
                    this.IsEnd = true;
                    return false;
                }

                this.CurrentNodeType = DataNodeType.Value;
            }

            return true;
        }

        public INodeReader ReadAsNode()
        {
            this.CheckEnd();

            if (this.CurrentNodeType == DataNodeType.Value)
            {
                throw new FormatException($"Unexpected token '{_row.Current}'.");
            }

            //return new TNodeReader(_reader.ReadLine().Split('\t'));
            return new TNodeReader(this.ReadRow());
        }

        private string[] ReadRow()
        {
            var stringBuilder = new StringBuilder(512);
            var readingString = false;
            var index = 0;

            while (_reader.Peek() > 0)
            {
                var current = (char)_reader.Read();
                var next = (char)_reader.Peek();

                if (current == '\r')
                {
                    if (next == '\n' && !readingString)
                    {
                        _reader.Read(); //read and skip "\r\n"
                        break;          //end of row
                    }
                    else
                    {
                        stringBuilder.Append(current);
                    }
                }
                else if (current == '\t')
                {
                    if (next == '"') //start of string
                    {
                        readingString = true;
                    }

                    stringBuilder.Append(current);
                }
                else if (current == '"')
                {
                    if (next == '\t' || next == '\r') //end of string
                    {
                        readingString = false;
                    }
                    else if (index == 0) //start of string
                    {
                        readingString = true;
                    }

                    stringBuilder.Append(current);
                }
                else
                {
                    stringBuilder.Append(current);
                }

                index++;
            }

            return stringBuilder.ToString().Split('\t');
        }

        public IValueReader ReadAsRaw()
        {
            throw new NotImplementedException();
        }

        public void SkipCurrentNode()
        {
            throw new NotImplementedException();
        }

        private void CheckEnd()
        {
            if (this.IsEnd)
            {
                throw new FormatException("The node has been read to the end.");
            }
        }

        private string TrimQuotation(string value)
        {
            if (String.IsNullOrWhiteSpace(value))
            {
                return value;
            }

            var start = value[0];

            if (start == '"')
            {
                value = value.Substring(1);
            }

            var end = value[value.Length - 1];

            if (end == '"')
            {
                value = value.Substring(0, value.Length - 1);
            }

            return value;
        }
    }
}
